package pl.edu.mimuw.irs.rcp.controller.part;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPolicy;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;

import pl.edu.mimuw.irs.core.model.design.IRSArc;
import pl.edu.mimuw.irs.core.model.design.IRSNodeInterface;
import pl.edu.mimuw.irs.core.model.petrinet.Arc;
import pl.edu.mimuw.irs.core.util.Position;
import pl.edu.mimuw.irs.rcp.controller.policy.NodeComponentEditPolicy;
import pl.edu.mimuw.irs.rcp.controller.policy.WorkflowXYLayoutEditPolicy;
import pl.edu.mimuw.irs.rcp.view.figure.FigureWrapper;

/**
 * @author Jakub Rauch
 * Created on: 2009-05-16
 */
public abstract class IRSAbstractNodeEditPart extends AbstractNodeEditPart implements IRSNodeEditPart {
	
	// *** Attributes

	// *** Methods

	@Override
	protected IFigure createFigure() {
		IRSNodeInterface node = (IRSNodeInterface)getModel();
		return getNodeShape().getShape(node.getPosition());
	}
	
	@Override
	public void activate() {
		super.activate();
	}
	@Override
	public void deactivate() {
		super.deactivate();
	}

	protected void refreshVisuals() {
		super.refreshVisuals();
		
		FigureWrapper wrapper = (FigureWrapper)getFigure();
		IRSNodeInterface node = (IRSNodeInterface)getModel();
		
		Label label;
		if (node.getChildren().size() > 0) {
			wrapper.setLineWidth(2);
			label = new Label(node.getId() + "\n" + node.getFragmentation().toString() + "\n[" + node.getChildren().size() + "]");
		} else {
			wrapper.setLineWidth(1);
			label = new Label(node.getId());
		}
		Font placeFont = new Font(null, "Arial", 8, SWT.NORMAL);

		label.setFont(placeFont);
		label.setTextAlignment(PositionConstants.CENTER);
        label.setTextPlacement(PositionConstants.SOUTH);
		label.setBounds(wrapper.getBounds().crop(IFigure.NO_INSETS));
		wrapper.setLabel(label);
	}
	
	public IRSNodeInterface getIRSNode() {
		return (IRSNodeInterface)getModel();
	}
	
	@Override
	protected List<Arc> getModelSourceConnections() {
		Set<Arc> allArcs = getIRSNode().getOutgoingArcs();
		List<Arc> visibleArcs = new LinkedList<Arc>();
		for (Arc arc : allArcs) {
			if (!isExpanded((IRSNodeInterface)arc.getSource()) &&
					isExpanded(((IRSNodeInterface)arc.getSource()).getParent()) &&
					!isExpanded((IRSNodeInterface)arc.getTarget())&&
					isExpanded(((IRSNodeInterface)arc.getTarget()).getParent()))
				visibleArcs.add((IRSArc)arc);
		}
		
		return visibleArcs;
	}
	
	private boolean isExpanded(IRSNodeInterface node) {
		if (node.isRoot() && node.isExpanded()) return true;
		else if (node.isExpanded() && isExpanded(node.getParent())) return true;
		else return false;
	}
	
	@Override
	protected List<IRSArc> getModelTargetConnections() {
		Set<Arc> allArcs = getIRSNode().getIncomingArcs();
		List<IRSArc> visibleArcs = new LinkedList<IRSArc>();
		for (Arc arc : allArcs) {
			if (!((IRSNodeInterface)arc.getSource()).isExpanded() &&
					((IRSNodeInterface)arc.getSource()).getParent().isExpanded() &&
					!((IRSNodeInterface)arc.getTarget()).isExpanded() &&
					((IRSNodeInterface)arc.getTarget()).getParent().isExpanded())
				visibleArcs.add((IRSArc)arc);
		}
		
		return visibleArcs;
	}
	
	@Override
	public void moveTo(Rectangle newBounds) {
		getIRSNode().setPosition(new Position(newBounds.x, newBounds.y));
		// XXX : powinno być przez listenera i zrobić w IRS rozmiar
		getFigure().setBounds(newBounds);
	}
	
	@Override
	public boolean isSelectable() {
		return true;
	}
	
	@Override
	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.LAYOUT_ROLE, new WorkflowXYLayoutEditPolicy());
		installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeComponentEditPolicy());
	}
	
	// *** Enums
	
	/*public enum NodeShape {
		PLACE(PlaceShape.class, 50, 50, new Color(null, new RGB(210, 210, 210))),
		RESOURCE(PlaceShape.class, 50, 50, new Color(null, new RGB(155, 255, 155))),
		TRANSITION(TransitionShape.class, 50, 50, new Color(null, new RGB(170, 170, 170))),
		ACTIVITY(TransitionShape.class, 50, 50, new Color(null, new RGB(155, 155, 255)));
		
		private Class<? extends Shape> shape;
		private int width;
		private int height;
		private Color color;
		
		NodeShape (Class<? extends Shape> shape, int width, int height, Color color) {
			this.shape = shape;
			this.width = width;
			this.height = height;
			this.color = color;
		}
		
		public FigureWrapper getShape(Position position) {
			Shape shapeInstance;
			FigureWrapper wrapper;
			try {
				Constructor<? extends Shape> constructor = shape.getConstructor();
				shapeInstance = constructor.newInstance();
				shapeInstance.setBounds(new Rectangle(position.getX(), position.getY(), width, height));
				shapeInstance.setBackgroundColor(color);
				wrapper = new FigureWrapper(shapeInstance);
			} catch (Exception e) {
				shapeInstance = new Triangle();
				shapeInstance.setBounds(new Rectangle(position.getX(), position.getY(), width, height));
				shapeInstance.setBackgroundColor(new Color(null, new RGB(255, 255, 0)));
				e.printStackTrace();// XXX : powinien być logger
				wrapper = new FigureWrapper(shapeInstance);
			}
			return wrapper;
		}
	}*/
}
